package org.example.sym;

import java.util.HashMap;

public class SymbolTable {
    private final HashMap<String, String> varsTable = new HashMap<>();
    protected final HashMap<String, String> sysVarsTable = new HashMap<>();
    private int blockDeep = 0;
    private final int belongDeep;
    private SymbolTable nextTable = null;
    private SymbolTable preTable = null;

    public SymbolTable(int deep, SymbolTable preTable) {
        belongDeep = deep;
        this.preTable = preTable;
    }

    public SymbolTable getTargetTable(int target_deep) {
        int startDeepCount = 0;
        SymbolTable p = this;
        while (p.belongDeep < target_deep) {
            if (p.nextTable == null) p.nextTable = new SymbolTable(++startDeepCount, p);
            p = p.nextTable;
        }
        return p;
    }

    public void deepBlockDeep() {
        blockDeep++;
    }

    public void shallowBlockDeep() {
        assert blockDeep != 0;
        blockDeep--;
        breakLink();
    }

    protected void insertNewVarByRef(String key, String refValue) {
        if (!varsTable.containsKey(key)) {
            varsTable.put(key, refValue);
        } else {
            assert false;
        }
    }

    public void insertNewVarWithBlockDeep(String key) {
        SymbolTable targetTable = getTargetTable(blockDeep);
        if (!targetTable.containVar(key)) {
            String ref_value = "@" + key + "_" + blockDeep;
            targetTable.insertNewVarByRef(key, ref_value);
        } else {
            assert false;
        }
    }

    public void insertSysVarIntoDeepI(String key) {
        SymbolTable targetTable = getTargetTable(1);
        targetTable.sysVarsTable.put(key, "systemKey");
    }

    public boolean containsSysVar(String key){
        SymbolTable targetTable = getTargetTable(1);
        return targetTable.sysVarsTable.containsKey(key);
    }

    protected boolean containVar(String key) {
        return varsTable.containsKey(key);
    }

    public boolean containVarFromBlockDeep(String key) {
        SymbolTable deepestTable = getTargetTable(blockDeep);
        SymbolTable p = deepestTable;
        while (p != null && !p.containVar(key)) {
            p = p.preTable;
        }
        if (p != null) {
            return true;
        }
        return false;
    }

    protected String varGetRef(String key) {
        return varsTable.get(key);
    }

    public String varGetRefFromBlockDeep(String key) {
        SymbolTable deepestTable = getTargetTable(blockDeep);
        SymbolTable p = deepestTable;
        while (p != null && !p.containVar(key)) {
            p = p.preTable;
        }

        if (p != null) {
            return p.varGetRef(key);
        }
        throw new RuntimeException("varGetRefFromBlockDeep 无符号-"+key);
    }

    private void breakLink() {
        SymbolTable targetTable = getTargetTable(blockDeep);
        targetTable.nextTable = null;
    }
}
